یکی از بحثهایی که در امنیت نرمافزارهای کاربردی مطرح میشود، مقابله با حملات SQL Injection (تزریق عبارات پرس و جو) است، اما باید دید برنامه ما در مقابله با این حملات آسیبپذیر است یا خیر؟
نمیتوان امنیت را به صورت صددرصد برای یک برنامه تضمین کرد، اما میتوان با استفاده از قواعد و همچنین تجربهای که دیگران کسب کردهاند، مشکلات یک نرمافزار را به کمترین حد رساند.
پیش از این که درصدد مقابله با این نوع حمله (SQL Injection) برآییم، بهتر است با آن آشنا شویم و سپس به حل آن اقدام کنیم. فرض کنید شما کد زیر را در در ASP.NET نوشتهاید
SqlConnection connection = new SqlConnection(connectionString);
SQlCommand command = new SqlCommand("SELECT * FROM testTable WHERE Name = ‘" + name.Text + “’”, connection);
برای اجرای دستور command، کاربر در کادر متنی name عبارت ali را چاپ میکند. سپس دستور به درستی اجرا و اطلاعات به کاربر نمایش داده میشود.
اما اگر کاربر عبارت زیر را وارد کند، چه اتفاقی میافتد؟
از آنجا که عبارت 1 = 1 یک عبارت همیشه درست بوده و با شرط دیگر OR شدهاست، پس همیشه شرط درست برقرار است. نتیجه جستجو همیشه برابر تمامی رکوردهای جدول است، که نتیجه دلخواه ما نیست.
پس دیدید با یک ترفند ساده میتوان از تمامی رکوردهای یک جدول در یک پایگاه داده خروجی گرفت.
اما این پایان ماجرا نیست، همانطورکه با یک شرط ساده، یک نفوذگر میتواند تمامیاطلاعات شما را ببیند، پس میتواند با قدری خلاقیت کارهای دیگری نیز انجام دهد؛ برای مثال عبارت زیر را وارد کند:
این عبارت باعث میشود نفوذگر تلاش کند جدول testable را از پایگاه داده شما حذف کند، اما نکتهای که وجود دارد این است، آیا شما جدولی به نام testable دارید یا خیر؟ یعنی نفوذگر چگونه این را تشخیص میدهد؟
این مورد به نحوه مدیریت خطا در کد شما مربوط میشود؛ این که چگونه شما خطاها را در سیستمتان مدیریت میکنید. اگر مدیریت خطای شما درست نباشد، کاربر میتواند از وجود یا نبود این جدول اطمینان پیدا کند.
اما چنانچه نفوذگر موفق شود دستورات SQL را از طریق این نقطه نفوذپذیر در برنامهتان اجرا کند میتواند کل پایگاه داده شما را مختل کند.
حال که با SQL Injection تا حدودی آشنا شدید، روشهایی را برای حل این موضوع ارائه میکنیم.
برای حل این مشکل یک راه ساده وجود دارد: عبارت SQL شما به صورت Dynamic نباشد، یعنی از روالهای ذخیره شده در پایگاه داده استفاده کنید، راه بعدی فیلتر کردن عبارت SQL است.
برای راه اول شما باید با نحوه نوشتن روالهای ذخیره شده در پایگاه داده آشنا شوید که این مورد از حوصله این مقاله خارج است.
اما راه بعدی را که سادهتر است، در داتنت و PHP بررسی میکنیم.
در داتنت برای فیلترکردن عبارات SQL از پارامترها استفاده میشود که همانند پارامترها در SQL Server عمل میکند. دستور را با استفاده از Parameter باز نویسی میکنیم.
SQlCommand command = new SqlCommand("SELECT * FROM testTable WHERE Name = @name", connection);
command.Parameters.Add("@name", SqlDbType.VarChar);
command.Parameters["@name"].Value = name.Text;
در خط اول به جای این که مقدار Name را از یک کادر متنی بگیریم، از یک متغیر به نام @name میگیریم، در خط بعدی به شیء command میگوییم. دستور SQL که قرار است اجرا شود یک متغیر از نوع VarChar به نام name@ دارد. در خط بعدی مقدار کادر متنی name را به عنوان مقدار آن متغیر قرار میدهیم.
حالا اگر هر دستوری را در کادر متنی name بنویسید، به عنوان یک پارامتر در نظر گرفته میشود و دستورات SQL که ممکن است درون آن وجود داشته باشد، اجرا نمیشوند.
اما در php برای حل این مشکل از تابع mysql_real_escape_string استفاده میکنیم.